<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
	<head>
		<title>Problems, Level 0</title>
<link href="../docs-assets/Breadcrumbs.css" rel="stylesheet" rev="stylesheet" type="text/css">
		<meta name="viewport" content="width=device-width initial-scale=1">
		<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
		<meta http-equiv="Content-Language" content="en-gb">

<link href="../docs-assets/Contents.css" rel="stylesheet" rev="stylesheet" type="text/css">
<link href="../docs-assets/Progress.css" rel="stylesheet" rev="stylesheet" type="text/css">
<link href="../docs-assets/Navigation.css" rel="stylesheet" rev="stylesheet" type="text/css">
<link href="../docs-assets/Fonts.css" rel="stylesheet" rev="stylesheet" type="text/css">
<link href="../docs-assets/Base.css" rel="stylesheet" rev="stylesheet" type="text/css">
<script>
function togglePopup(material_id) {
  var popup = document.getElementById(material_id);
  popup.classList.toggle("show");
}
</script>

<link href="../docs-assets/Popups.css" rel="stylesheet" rev="stylesheet" type="text/css">
<link href="../docs-assets/Colours.css" rel="stylesheet" rev="stylesheet" type="text/css">
		
	</head>
	<body class="commentary-font">
		<nav role="navigation">
		<h1><a href="../index.html"><img src="../docs-assets/Inform.png" height=72> </a></h1>
<ul><li><a href="../index.html">home</a></li>
</ul><h2>Compiler</h2><ul>
<li><a href="../structure.html">structure</a></li>
<li><a href="../inbuildn.html">inbuild</a></li>
<li><a href="../inform7n.html">inform7</a></li>
<li><a href="../intern.html">inter</a></li>
<li><a href="../services.html">services</a></li>
<li><a href="../secrets.html">secrets</a></li>
</ul><h2>Other Tools</h2><ul>
<li><a href="../inblorbn.html">inblorb</a></li>
<li><a href="../inform6.html">inform6</a></li>
<li><a href="../inpolicyn.html">inpolicy</a></li>
</ul><h2>Resources</h2><ul>
<li><a href="../extensions.html">extensions</a></li>
<li><a href="../kits.html">kits</a></li>
</ul><h2>Repository</h2><ul>
<li><a href="https://github.com/ganelson/inform"><img src="../docs-assets/github.png" height=0> github</a></li>
</ul><h2>Related Projects</h2><ul>
<li><a href="https://github.com/ganelson/inweb"><img src="../docs-assets/github.png" height=0> inweb</a></li>
<li><a href="https://github.com/ganelson/intest"><img src="../docs-assets/github.png" height=0> intest</a></li>
</ul>
		</nav>
		<main role="main">
		<!-- Weave of 'Problems, Level 0' generated by inweb -->
<div class="breadcrumbs">
    <ul class="crumbs"><li><a href="../index.html">Home</a></li><li><a href="../services.html">Services</a></li><li><a href="index.html">problems</a></li><li><a href="index.html#2">Chapter 2: Problems</a></li><li><b>Problems, Level 0</b></li></ul></div>
<p class="purpose">To handle fatal errors and establish how problem sigils work.</p>

<ul class="toc"><li><a href="2-pl0.html#SP1">&#167;1. Sudden exits</a></li><li><a href="2-pl0.html#SP3">&#167;3. Configuration</a></li><li><a href="2-pl0.html#SP6">&#167;6. Sigils</a></li></ul><hr class="tocbar">

<p class="commentary firstcommentary"><a id="SP1" class="paragraph-anchor"></a><b>&#167;1. Sudden exits.</b>In my beginning is my end: this lowest level of the error-handling system
deals with systemic collapses, and it begins with the exit itself. Note that
the exit code depends on whether the parent tool, perversely perhaps, actually
wants to have issued a given problem &mdash; this is used when testing Inform.
</p>

<p class="commentary">By convention our exit codes are 0 for success, 1 for failure, and 2 for a
filing-system-related failure.
</p>

<pre class="displayed-code all-displayed-code code-font">
<span class="identifier-syntax">text_stream</span><span class="plain-syntax"> *</span><span class="identifier-syntax">sigil_of_required_problem</span><span class="plain-syntax"> = </span><span class="identifier-syntax">NULL</span><span class="plain-syntax">;</span>

<span class="reserved-syntax">int</span><span class="plain-syntax"> </span><span class="identifier-syntax">sigil_of_required_problem_found</span><span class="plain-syntax"> = </span><span class="identifier-syntax">FALSE</span><span class="plain-syntax">;</span>
<span class="reserved-syntax">int</span><span class="plain-syntax"> </span><span class="identifier-syntax">echo_problem_message_sigils</span><span class="plain-syntax"> = </span><span class="identifier-syntax">FALSE</span><span class="plain-syntax">;</span>
<span class="reserved-syntax">int</span><span class="plain-syntax"> </span><span class="identifier-syntax">crash_on_all_problems</span><span class="plain-syntax"> = </span><span class="identifier-syntax">FALSE</span><span class="plain-syntax">;</span>

<span class="reserved-syntax">void</span><span class="plain-syntax"> </span><span class="function-syntax">ProblemSigils::exit</span><button class="popup" onclick="togglePopup('usagePopup1')"><span class="comment-syntax">?</span><span class="popuptext" id="usagePopup1">Usage of <span class="code-font"><span class="function-syntax">ProblemSigils::exit</span></span>:<br/><a href="2-pl0.html#SP2">&#167;2</a><br/>Problems, Level 2 - <a href="2-pl2.html#SP15">&#167;15</a><br/>Problems, Level 3 - <a href="2-pl3.html#SP3">&#167;3</a>, <a href="2-pl3.html#SP11">&#167;11</a></span></button><span class="plain-syntax">(</span><span class="reserved-syntax">int</span><span class="plain-syntax"> </span><span class="identifier-syntax">code</span><span class="plain-syntax">) {</span>
<span class="plain-syntax">    </span><span class="reserved-syntax">if</span><span class="plain-syntax"> ((</span><span class="identifier-syntax">sigil_of_required_problem</span><span class="plain-syntax">) &amp;&amp; (</span><span class="identifier-syntax">sigil_of_required_problem_found</span><span class="plain-syntax"> == </span><span class="identifier-syntax">FALSE</span><span class="plain-syntax">))</span>
<span class="plain-syntax">        </span><span class="identifier-syntax">exit</span><span class="plain-syntax">(0); </span><span class="comment-syntax"> so that the problem test case will fail in </span><span class="extract"><span class="extract-syntax">intest</span></span>
<span class="plain-syntax">    </span><span class="identifier-syntax">exit</span><span class="plain-syntax">(</span><span class="identifier-syntax">code</span><span class="plain-syntax">);</span>
<span class="plain-syntax">}</span>
</pre>
<p class="commentary firstcommentary"><a id="SP2" class="paragraph-anchor"></a><b>&#167;2. </b>The following function has had an amusing evolution over the years. It does
something nobody is ever supposed to do: deliberately crashes the process.
At one time it executed <span class="extract"><span class="extract-syntax">int x = 1/0;</span></span>, but compilers got wise to that, or
else would detect that such an expression had no side effects and was not used.
What we now do is to dereference a null pointer, while apparently trying to make
use of the result.
</p>

<pre class="displayed-code all-displayed-code code-font">
<span class="reserved-syntax">void</span><span class="plain-syntax"> </span><span class="function-syntax">ProblemSigils::force_crash</span><button class="popup" onclick="togglePopup('usagePopup2')"><span class="comment-syntax">?</span><span class="popuptext" id="usagePopup2">Usage of <span class="code-font"><span class="function-syntax">ProblemSigils::force_crash</span></span>:<br/>Problems, Level 2 - <a href="2-pl2.html#SP10">&#167;10</a>, <a href="2-pl2.html#SP15">&#167;15</a><br/>Problems, Level 3 - <a href="2-pl3.html#SP3">&#167;3</a></span></button><span class="plain-syntax">(</span><span class="reserved-syntax">void</span><span class="plain-syntax">) {</span>
<span class="plain-syntax">    </span><span class="identifier-syntax">STREAM_FLUSH</span><span class="plain-syntax">(</span><span class="identifier-syntax">STDOUT</span><span class="plain-syntax">);</span>
<span class="plain-syntax">    </span><span class="identifier-syntax">STREAM_FLUSH</span><span class="plain-syntax">(</span><span class="identifier-syntax">DL</span><span class="plain-syntax">);</span>
<span class="plain-syntax">    </span><span class="identifier-syntax">WRITE_TO</span><span class="plain-syntax">(</span><span class="identifier-syntax">STDERR</span><span class="plain-syntax">,</span>
<span class="plain-syntax">        </span><span class="string-syntax">"*** Intentionally crashing to force stack backtrace to console logs ***\n"</span><span class="plain-syntax">);</span>
<span class="plain-syntax">    </span><span class="identifier-syntax">STREAM_FLUSH</span><span class="plain-syntax">(</span><span class="identifier-syntax">STDERR</span><span class="plain-syntax">);</span>
<span class="plain-syntax">    </span><span class="identifier-syntax">parse_node</span><span class="plain-syntax"> *</span><span class="identifier-syntax">PN</span><span class="plain-syntax"> = </span><span class="identifier-syntax">NULL</span><span class="plain-syntax">; </span><span class="identifier-syntax">LOG</span><span class="plain-syntax">(</span><span class="string-syntax">"$T"</span><span class="plain-syntax">, </span><span class="identifier-syntax">PN</span><span class="plain-syntax">-&gt;</span><span class="identifier-syntax">next</span><span class="plain-syntax">);</span>
<span class="plain-syntax">    </span><a href="2-pl0.html#SP1" class="function-link"><span class="function-syntax">ProblemSigils::exit</span></a><span class="plain-syntax">(1); </span><span class="comment-syntax"> should never in fact be reached</span>
<span class="plain-syntax">}</span>
</pre>
<p class="commentary firstcommentary"><a id="SP3" class="paragraph-anchor"></a><b>&#167;3. Configuration.</b>Inform calls this in response to its <span class="extract"><span class="extract-syntax">-require-problem</span></span> command line switch:
</p>

<pre class="displayed-code all-displayed-code code-font">
<span class="reserved-syntax">void</span><span class="plain-syntax"> </span><span class="function-syntax">ProblemSigils::require</span><span class="plain-syntax">(</span><span class="identifier-syntax">text_stream</span><span class="plain-syntax"> *</span><span class="identifier-syntax">sigil</span><span class="plain-syntax">) {</span>
<span class="plain-syntax">    </span><span class="identifier-syntax">sigil_of_required_problem</span><span class="plain-syntax"> = </span><span class="identifier-syntax">Str::duplicate</span><span class="plain-syntax">(</span><span class="identifier-syntax">sigil</span><span class="plain-syntax">);</span>
<span class="plain-syntax">}</span>
</pre>
<p class="commentary firstcommentary"><a id="SP4" class="paragraph-anchor"></a><b>&#167;4. </b>And this in response to <span class="extract"><span class="extract-syntax">-sigils</span></span>, which causes the sigil of any problem to
be echoed to standard output (i.e., printed). Again, this is useful in testing.
</p>

<pre class="displayed-code all-displayed-code code-font">
<span class="reserved-syntax">void</span><span class="plain-syntax"> </span><span class="function-syntax">ProblemSigils::echo_sigils</span><span class="plain-syntax">(</span><span class="reserved-syntax">int</span><span class="plain-syntax"> </span><span class="identifier-syntax">state</span><span class="plain-syntax">) {</span>
<span class="plain-syntax">    </span><span class="identifier-syntax">echo_problem_message_sigils</span><span class="plain-syntax"> = </span><span class="identifier-syntax">state</span><span class="plain-syntax">;</span>
<span class="plain-syntax">}</span>
</pre>
<p class="commentary firstcommentary"><a id="SP5" class="paragraph-anchor"></a><b>&#167;5. </b>And this in response to <span class="extract"><span class="extract-syntax">-crash-all</span></span>, an ugly expedient for working with
Inform in the debugger.
</p>

<pre class="displayed-code all-displayed-code code-font">
<span class="reserved-syntax">void</span><span class="plain-syntax"> </span><span class="function-syntax">ProblemSigils::crash_on_problems</span><span class="plain-syntax">(</span><span class="reserved-syntax">int</span><span class="plain-syntax"> </span><span class="identifier-syntax">state</span><span class="plain-syntax">) {</span>
<span class="plain-syntax">    </span><span class="identifier-syntax">crash_on_all_problems</span><span class="plain-syntax"> = </span><span class="identifier-syntax">state</span><span class="plain-syntax">;</span>
<span class="plain-syntax">}</span>
</pre>
<p class="commentary firstcommentary"><a id="SP6" class="paragraph-anchor"></a><b>&#167;6. Sigils.</b>Every problem message in Inform is identified by a sigil, a short alphanumeric
symbol. The <span class="extract"><span class="extract-syntax">_p_</span></span> notation is used to write these; this expands to the name in
double quotes followed by the source section and line number at which it is
generated.
</p>

<pre class="definitions code-font"><span class="definition-keyword">define</span> <span class="identifier-syntax">_p_</span><span class="plain-syntax">(</span><span class="identifier-syntax">sigil</span><span class="plain-syntax">) #</span><span class="identifier-syntax">sigil</span><span class="plain-syntax">, </span><span class="identifier-syntax">__FILE__</span><span class="plain-syntax">, </span><span class="identifier-syntax">__LINE__</span>
</pre>
<p class="commentary firstcommentary"><a id="SP7" class="paragraph-anchor"></a><b>&#167;7. </b>That means that when a <span class="extract"><span class="extract-syntax">_p_</span></span> argument is given to a function, it is actually
a list of three arguments, matching the <span class="extract"><span class="extract-syntax">SIGIL_ARGUMENTS</span></span> prototype. <span class="extract"><span class="extract-syntax">SIGIL_ARGUMENTS</span></span>
appears as a pseudo-argument in the function prototypes of the many of the
functions in this module as a result.
</p>

<p class="commentary">Each such function should either <span class="extract"><span class="extract-syntax">ACT_ON_SIGIL</span></span> itself or else pass over to
another problem function, using <span class="extract"><span class="extract-syntax">PASS_SIGIL</span></span> as the pseudo-argument.
</p>

<pre class="definitions code-font"><span class="definition-keyword">define</span> <span class="constant-syntax">SIGIL_ARGUMENTS</span><span class="plain-syntax"> </span><span class="reserved-syntax">char</span><span class="plain-syntax"> *</span><span class="identifier-syntax">sigil</span><span class="plain-syntax">, </span><span class="reserved-syntax">char</span><span class="plain-syntax"> *</span><span class="identifier-syntax">file</span><span class="plain-syntax">, </span><span class="reserved-syntax">int</span><span class="plain-syntax"> </span><span class="identifier-syntax">line</span>
<span class="definition-keyword">define</span> <span class="constant-syntax">PASS_SIGIL</span><span class="plain-syntax"> </span><span class="identifier-syntax">sigil</span><span class="plain-syntax">, </span><span class="identifier-syntax">file</span><span class="plain-syntax">, </span><span class="identifier-syntax">line</span>
</pre>
<p class="commentary firstcommentary"><a id="SP8" class="paragraph-anchor"></a><b>&#167;8. </b>We will maintain the following variables. The distinction is that the
"unlinked" one holds the sigil of a message which is next up to be hyperlinked
to documentation; <span class="extract"><span class="extract-syntax">sigil_of_latest_unlinked_problem</span></span> is then emptied when this
is done, whereas <span class="extract"><span class="extract-syntax">sigil_of_latest_problem</span></span> keeps its value until the next
problem is issued.
</p>

<pre class="displayed-code all-displayed-code code-font">
<span class="identifier-syntax">text_stream</span><span class="plain-syntax"> *</span><span class="identifier-syntax">sigil_of_latest_problem</span><span class="plain-syntax"> = </span><span class="identifier-syntax">NULL</span><span class="plain-syntax">;</span>
<span class="identifier-syntax">text_stream</span><span class="plain-syntax"> *</span><span class="identifier-syntax">sigil_of_latest_unlinked_problem</span><span class="plain-syntax"> = </span><span class="identifier-syntax">NULL</span><span class="plain-syntax">;</span>
</pre>
<p class="commentary firstcommentary"><a id="SP9" class="paragraph-anchor"></a><b>&#167;9. </b>So, then, the following long macro is how a function "acts" on a sigil:
</p>

<pre class="definitions code-font"><span class="definition-keyword">define</span> <span class="constant-syntax">ACT_ON_SIGIL</span>
<span class="plain-syntax">    </span><span class="identifier-syntax">LOG</span><span class="plain-syntax">(</span><span class="string-syntax">"Problem %s issued from %s, line %d\n"</span><span class="plain-syntax">, </span><span class="identifier-syntax">sigil</span><span class="plain-syntax">, </span><span class="identifier-syntax">file</span><span class="plain-syntax">, </span><span class="identifier-syntax">line</span><span class="plain-syntax">);</span>
<span class="plain-syntax">    </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">sigil_of_latest_unlinked_problem</span><span class="plain-syntax"> == </span><span class="identifier-syntax">NULL</span><span class="plain-syntax">)</span>
<span class="plain-syntax">        </span><span class="identifier-syntax">sigil_of_latest_unlinked_problem</span><span class="plain-syntax"> = </span><span class="identifier-syntax">Str::new</span><span class="plain-syntax">();</span>
<span class="plain-syntax">    </span><span class="reserved-syntax">else</span>
<span class="plain-syntax">        </span><span class="identifier-syntax">Str::clear</span><span class="plain-syntax">(</span><span class="identifier-syntax">sigil_of_latest_unlinked_problem</span><span class="plain-syntax">);</span>
<span class="plain-syntax">    </span><span class="identifier-syntax">WRITE_TO</span><span class="plain-syntax">(</span><span class="identifier-syntax">sigil_of_latest_unlinked_problem</span><span class="plain-syntax">, </span><span class="string-syntax">"%s"</span><span class="plain-syntax">, </span><span class="identifier-syntax">sigil</span><span class="plain-syntax">);</span>
<span class="plain-syntax">    </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">sigil_of_latest_problem</span><span class="plain-syntax"> == </span><span class="identifier-syntax">NULL</span><span class="plain-syntax">)</span>
<span class="plain-syntax">        </span><span class="identifier-syntax">sigil_of_latest_problem</span><span class="plain-syntax"> = </span><span class="identifier-syntax">Str::new</span><span class="plain-syntax">();</span>
<span class="plain-syntax">    </span><span class="reserved-syntax">else</span>
<span class="plain-syntax">        </span><span class="identifier-syntax">Str::clear</span><span class="plain-syntax">(</span><span class="identifier-syntax">sigil_of_latest_problem</span><span class="plain-syntax">);</span>
<span class="plain-syntax">    </span><span class="identifier-syntax">WRITE_TO</span><span class="plain-syntax">(</span><span class="identifier-syntax">sigil_of_latest_problem</span><span class="plain-syntax">, </span><span class="string-syntax">"%s"</span><span class="plain-syntax">, </span><span class="identifier-syntax">sigil</span><span class="plain-syntax">);</span>
<span class="plain-syntax">    </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">Str::eq</span><span class="plain-syntax">(</span><span class="identifier-syntax">sigil_of_required_problem</span><span class="plain-syntax">, </span><span class="identifier-syntax">sigil_of_latest_problem</span><span class="plain-syntax">))</span>
<span class="plain-syntax">        </span><span class="identifier-syntax">sigil_of_required_problem_found</span><span class="plain-syntax"> = </span><span class="identifier-syntax">TRUE</span><span class="plain-syntax">;</span>
<span class="plain-syntax">    </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">echo_problem_message_sigils</span><span class="plain-syntax">) {</span>
<span class="plain-syntax">        </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">Str::get_first_char</span><span class="plain-syntax">(</span><span class="identifier-syntax">sigil_of_latest_problem</span><span class="plain-syntax">) == </span><span class="character-syntax">'W'</span><span class="plain-syntax">)</span>
<span class="plain-syntax">            </span><span class="identifier-syntax">WRITE_TO</span><span class="plain-syntax">(</span><span class="identifier-syntax">STDERR</span><span class="plain-syntax">, </span><span class="string-syntax">"Warning__ %S\n"</span><span class="plain-syntax">, </span><span class="identifier-syntax">sigil_of_latest_problem</span><span class="plain-syntax">);</span>
<span class="plain-syntax">        </span><span class="reserved-syntax">else</span>
<span class="plain-syntax">            </span><span class="identifier-syntax">WRITE_TO</span><span class="plain-syntax">(</span><span class="identifier-syntax">STDERR</span><span class="plain-syntax">, </span><span class="string-syntax">"Problem__ %S\n"</span><span class="plain-syntax">, </span><span class="identifier-syntax">sigil_of_latest_problem</span><span class="plain-syntax">);</span>
<span class="plain-syntax">    }</span>
</pre>
<nav role="progress"><div class="progresscontainer">
    <ul class="progressbar"><li class="progressprev"><a href="1-pm.html">&#10094;</a></li><li class="progresschapter"><a href="P-wtmd.html">P</a></li><li class="progresschapter"><a href="1-pm.html">1</a></li><li class="progresscurrentchapter">2</li><li class="progresscurrent">pl0</li><li class="progresssection"><a href="2-pl1.html">pl1</a></li><li class="progresssection"><a href="2-pl2.html">pl2</a></li><li class="progresssection"><a href="2-pl3.html">pl3</a></li><li class="progressnext"><a href="2-pl1.html">&#10095;</a></li></ul></div>
</nav><!-- End of weave -->

		</main>
	</body>
</html>

